#include <algorithm> 
#include <functional> 
#include <cctype>
#include <locale>
#include "GpuParser.h"
#include "XpathQueryForParser.h"
#include "Utilities.h"

// trim function
std::string &ltrim(std::string &s);
std::string &rtrim(std::string &s);
std::string trim(std::string inputChar);

GpuParser::GpuParser(std::string xmlFile)
{	
	if (!doc.load_file(xmlFile.c_str())){
		throw "XML open failed!";
	}
}

std::string GpuParser::getAppType()
{
	pugi::xpath_query query(XpathQueryForParser::xpathAppType);

	pugi::xpath_node_set result = query.evaluate_node_set(doc);

	const char* answer = "";
	if (result.size() > 0) {
		answer = result[0].node().child_value();		
	}

	return trim(answer);
}

std::string GpuParser::getSearchPhase()
{
	pugi::xpath_query query(XpathQueryForParser::xpathSearchPhase);

	pugi::xpath_node_set result = query.evaluate_node_set(doc);

	const char* answer = "";
	if (result.size() > 0) {				
		answer = result[0].node().name();
	}

	return trim(answer);
}

std::string GpuParser::getInvertedListPath()
{
	pugi::xpath_query query(XpathQueryForParser::xpathInvertedListPath);

	pugi::xpath_node_set result = query.evaluate_node_set(doc);

	const char* answer = "";
	if (result.size() > 0) {				
		answer = result[0].node().child_value();
	}

	return trim(answer);
}

std::string GpuParser::getInvertedIndexLengthFile()
{
	pugi::xpath_query query(XpathQueryForParser::xpathInvertedIndexLengthFile);

	pugi::xpath_node_set result = query.evaluate_node_set(doc);

	const char* answer = "";
	if (result.size() > 0) {				
		answer = result[0].node().child_value();
	}

	return trim(answer);
}

std::string GpuParser::getSearchMethod()
{
	pugi::xpath_query query(XpathQueryForParser::xpathSearchMethod);

	pugi::xpath_node_set result = query.evaluate_node_set(doc);

	const char* answer = "";
	if (result.size() > 0) {				
		answer = result[0].node().name();
	}

	return trim(answer);
}

int GpuParser::getNumOfDocToExpand()
{
	pugi::xpath_query query(XpathQueryForParser::xpathNumOfDocToExpand);

	pugi::xpath_node_set result = query.evaluate_node_set(doc);

	const char* answer = "";
	if (result.size() > 0) {				
		answer = result[0].node().child_value();
	}

	return strToInt(trim(answer));
}

int GpuParser::getTotalDimension()
{
	pugi::xpath_query query(XpathQueryForParser::xpathTotalDimension);

	pugi::xpath_node_set result = query.evaluate_node_set(doc);

	const char* answer = "";
	if (result.size() > 0) {				
		answer = result[0].node().child_value();
	}

	return strToInt(trim(answer));
}

int GpuParser::getTopK()
{
	pugi::xpath_query query(XpathQueryForParser::xpathTopK);

	pugi::xpath_node_set result = query.evaluate_node_set(doc);

	const char* answer = "";
	if (result.size() > 0) {				
		answer = result[0].node().child_value();
	}

	return strToInt(trim(answer));
}

std::vector<int> GpuParser::getMinDomainForAllDimension()
{
	pugi::xpath_query query(XpathQueryForParser::xpathMinDomainForAllDimension);

	pugi::xpath_node_set result = query.evaluate_node_set(doc);

	const char* answer = "";
	if (result.size() > 0) {				
		answer = result[0].node().child_value();
	}

	return splitAndParseInt(trim(answer));
}

std::vector<int> GpuParser::getMaxDomainForAllDimension()
{
	pugi::xpath_query query(XpathQueryForParser::xpathMaxDomainForAllDimension);

	pugi::xpath_node_set result = query.evaluate_node_set(doc);

	const char* answer = "";
	if (result.size() > 0) {				
		answer = result[0].node().child_value();
	}

	return splitAndParseInt(trim(answer));
}

void GpuParser::getQuerySet(std::vector<GpuQuery> &querySet)
{
	pugi::xpath_query query(XpathQueryForParser::xpathQuerySet);

	pugi::xpath_node_set result = query.evaluate_node_set(doc);

	for (int i=0; i<result.size(); i++)
	{		
		GpuQuery* queryTemp = new GpuQuery();
		pugi::xml_node currentNode = result[i].node();
		queryTemp->queryID = strToInt(trim(currentNode.select_single_node(XpathQueryForParser::xpathQuerySet_QueryId).node().child_value()));
		queryTemp->keywords = splitAndParseInt(trim(currentNode.select_single_node(XpathQueryForParser::xpathQuerySet_keywords).node().child_value()));
		queryTemp->upwardSearchBound = strToFloat(trim(currentNode.select_single_node(XpathQueryForParser::xpathQuerySet_UpwardSearchBound).node().child_value()));
		queryTemp->downwardSearchBound = strToFloat(trim(currentNode.select_single_node(XpathQueryForParser::xpathQuerySet_DownwardSearchBound).node().child_value()));
		queryTemp->numOfDimensionToSearch = strToInt(trim(currentNode.select_single_node(XpathQueryForParser::xpathQuerySet_NumOfDimensionToSearch).node().child_value()));
		queryTemp->aggregateFunction = strToInt(trim(currentNode.select_single_node(XpathQueryForParser::xpathQuerySet_AggregateFunction).node().child_value()));
		getDimensionSetForQuerySet(currentNode, queryTemp->dimensionSet, queryTemp->numOfDimension);
		querySet.push_back(*queryTemp);
	}		
}

void GpuParser::getDimensionSetForQuerySet(pugi::xml_node root, std::vector<GpuDimension> &dimensionSet, int& dimensionSetSize)
{

	pugi::xpath_node_set result = root.select_nodes(XpathQueryForParser::xpathQuerySet_DimensionToSearch);

	dimensionSetSize = result.size();

	for (int i=0; i<result.size(); i++)
	{		
		pugi::xml_node currentNode = result[i].node();

		GpuDimension *dimensionTemp = new GpuDimension();
		dimensionTemp->dimension = strToInt(trim(currentNode.child_value()));
		dimensionTemp->weight = strToFloat(trim(currentNode.select_single_node(XpathQueryForParser::xpathQuerySet_Weight).node().child_value()));
		dimensionTemp->distanceFunctionPerDimension = strToInt(trim(currentNode.select_single_node(XpathQueryForParser::xpathQuerySet_DistanceFunctionPerDimension).node().child_value()));
		dimensionSet.push_back(*dimensionTemp);
	}		
}


